package org.jing.ext.shell;

import org.jing.core.lang.JingException;
import org.jing.core.logger.JingLogger;
import org.jing.core.util.GenericUtil;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * Description: 操作系统指令操作. <br>
 *
 * @author bks <br>
 * @since 2021-02-03 <br>
 */
@SuppressWarnings({ "unused", "UnusedReturnValue", "WeakerAccess" })
public class CommandUtil {
    private static final JingLogger LOGGER = JingLogger.getLogger(CommandUtil.class);

    /**
     * Description: 执行操作系统指令. <br>
     * 注意, 在使用中遇到了这样的问题: 无法正确加载当前用户拥有的环境变量, 只能使用全局的.
     * 即使调用两次该方法, 在前面一次设置了环境变量也没用, 检索后发现是因为<b>Runtime.getRuntime().exec(cmd)</b>会创建一个临时的独立进程,
     * 两个进程之间当然不会共享环境变量. 因此碰到在同一新进程下shell命令的情况请使用下面的<b>executeShell(String[] shellCommands)</b>.
     *
     * @param command 命令行 <br>
     * @return <br>
     */
    @SuppressWarnings("Duplicates")
    public static String executeCommand(String command) {
        Process process;
        try {
            LOGGER.info("Try to execute shell: {}", command);
            String[] cmd = { "/bin/sh", "-c", command };
            process = Runtime.getRuntime().exec(cmd);
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }

        if (null == process) {
            LOGGER.info("There is no PId");
            return "";
        }
        LOGGER.info("PId: {}", process.toString());

        try (
            BufferedReader commReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 1024);
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()), 1024)
        ) {
            process.waitFor();
            StringBuilder stbr = new StringBuilder();
            String line;
            while (null != (line = commReader.readLine())) {
                if (stbr.length() != 0) {
                    stbr.append("\n");
                }
                stbr.append(line);
            }
            while (null != (line = errorReader.readLine())) {
                if (stbr.length() != 0) {
                    stbr.append("\n");
                }
                stbr.append("Execute fail: ");
                stbr.append(line);
            }
            String result = stbr.toString();
            LOGGER.info("Result: {}", result);
            return result;
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }
    }

    /**
     * Description: 新建一个进程, 然后在同一个进程里依次执行多条shell命令. <br>
     *
     * @param commands 多条命令行 <br>
     */
    @SuppressWarnings("Duplicates")
    public static String[] executeCommands(String[] commands) {
        try {
            Process process;
            ProcessBuilder builder = new ProcessBuilder();
            String[] cmd;
            String[] results = new String[GenericUtil.count(commands)];
            for (int i$ = 0, size$ = results.length; i$ < size$; i$++) {
                LOGGER.info("Try to execute shell: {}", commands[i$]);
                cmd = new String[]{ "/bin/sh", "-c", commands[i$] };
                builder.command(cmd);
                process = builder.start();
                LOGGER.debug("PId: {}", process.toString());
                try (
                    BufferedReader commReader = new BufferedReader(new InputStreamReader(process.getInputStream()), 1024);
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()), 1024)
                ) {
                    process.waitFor();
                    StringBuilder stbr = new StringBuilder();
                    String line;
                    while (null != (line = commReader.readLine())) {
                        if (stbr.length() != 0) {
                            stbr.append("\n");
                        }
                        stbr.append(line);
                    }
                    while (null != (line = errorReader.readLine())) {
                        if (stbr.length() != 0) {
                            stbr.append("\n");
                        }
                        stbr.append("Execute fail: ");
                        stbr.append(line);
                    }
                    String result = stbr.toString();
                    LOGGER.debug("Result: {}", result);
                    results[i$] = result;
                }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }
            }
            return results;
        }
        catch (JingException e) {
            throw e;
        }
        catch (Throwable t) {
            throw new JingException(t);
        }
    }
}
